package cate.game.role.pvp.eliterace;

import cate.common.table.d.GDEliteRace;
import cate.common.table.d.GDObj;
import cate.game.pvp.eliterace.data.*;
import cate.game.pvp.eliterace.util.EliteRaceSpecUtils;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.pvp.eliterace.msg.EliteRaceBetDataResp;
import cate.game.role.pvp.eliterace.msg.EliteRaceBetReq;
import cate.game.role.pvp.eliterace.vo.EliteRaceBetRdVO;
import cate.game.role.pvp.eliterace.vo.EliteRaceBetVO;
import com.google.common.collect.Maps;
import easy.java.dev.note.NoteClass;
import easy.java.practice.errorcode.EcResult;
import lombok.Data;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static cate.game.client.msg.MsgSender.send;

@Data
@NoteClass("精英赛竞猜数据")
public class EliteRaceBetPO extends RoleDependent {
    public Map<String, EliteRaceBetVO> rdMap;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (Objects.isNull(rdMap)) {
            rdMap = Maps.newHashMap();
        }
    }

    @Override
    public void onEnter() {
        super.onEnter();
        handleCalBet();
    }

    public EcResult<Void> checkBet(EliteRaceBetReq req) {
        EcResult<Void> r = new EcResult<>();

        EliteRaceKV kv = role.getGame().pvp.eliteRace.getDataManager().getData();
        EliteRaceSpec spec = kv.getSpec();

        if (!Objects.equals(req.spec, spec)) {
            return r.fail("当前无法竞猜!");
        }

        EliteRaceSpec querySpec = EliteRaceSpec.of(
                spec.getSeason(),
                spec.getPeriod(),
                spec.getGroup(),
                spec.getRound()
        );

        EliteRaceBetVO betVO = rdMap.get(querySpec.toString());
        if (Objects.nonNull(betVO)) {
            return r.fail("已经参与竞猜本轮,无需重复参与!");
        }
        if (rdMap.size() >= GDEliteRace.MAX_BET_TIMES) {
            return r.fail("竞猜次数不足，请在下期活动再参与");
        }
        return r.success();
    }

    public void updateNotice(EliteRaceSpec spec, EliteRaceBetRecord record) {
        send(role::sendNow, new EliteRaceBetDataResp(0, rdMap.size(), EliteRaceBetRdVO.of(record), rdMap.get(spec.toString())));
    }

    public void handleBet(EliteRaceBetReq req, EliteRaceBetVO betVO) {
        role.getHistory().action.eliteRaceBet();
        rdMap.put(betVO.getSpec().toString(), betVO);
    }

    public void handleBetData() {
        EliteRaceKV kv = role.getGame().pvp.eliteRace.getDataManager().getData();
        EliteRaceSpec spec = EliteRaceSpec.of(
                kv.getSpec().getSeason(),
                kv.getSpec().getPeriod(),
                (byte) 0,
                kv.getSpec().getRound()
        );
        EcResult<EliteRaceBetRecord> r = role.getGame().pvp.eliteRace.getHandler().handleGetBetRecord(spec);
        if (r.ok()) {
            updateNotice(spec, r.data);
        }
    }

    public void addCoins(long added) {
        if (added > 0) {
            MixRes rwd = new MixRes();
            rwd.addItem(new MixResItem(GDObj.Type.NUM, GDObj.Num.RACE_POINT, added));
            rwd.add(role);
            role.getGame().notice.dialogReward(role, rwd);
        }
    }

    public void handleBetRwd(EliteRaceBetRecord betRecord) {
        if (rdMap.isEmpty()) {
            return;
        }
        if (!rdMap.containsKey(betRecord.getSpec().toString())) {
            return;
        }

        EliteRaceBetVO betVO = rdMap.get(betRecord.getSpec().toString());
        if (betVO.getSide() == betRecord.getWinner()) {
            if (betVO.exchange == (byte) 1) {
                return;
            }
            betVO.exchange = (byte) 1;
            role.getHistory().action.eliteRaceBetCorrect();
            addCoins(betVO.getGetCoins());

            updateNotice(betRecord.getSpec(), betRecord);
        } else {
            if (betVO.exchange == (byte) 1) {
                return;
            }
            betVO.exchange = (byte) 1;
            MixRes rwd = new MixRes(GDEliteRace.BET_WRONG_REWARD);
            rwd.add(role);
            role.getGame().notice.dialogReward(role, rwd);
            updateNotice(betRecord.getSpec(), betRecord);
        }
    }

    public byte hasBet(EliteRaceSpec spec) {
        if (!EliteRaceSpecUtils.isBetRwd(spec)) {
            return 0;
        }

        return Objects.isNull(rdMap.get(spec.toString())) ? (byte) 1 : (byte) 0;
    }

    public void handleCalBet() {
        Map<String, EliteRaceBetVO> betMap = rdMap.entrySet().stream()
                .filter(entry -> entry.getValue().getExchange() == (byte) 0)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        if (CollectionUtils.isEmpty(betMap)) {
            return;
        }

        EcResult<List<EliteRaceBetRecord>> r = role.getGame().pvp.eliteRace.getHandler().handleQueryAll();
        if (!r.ok()) {
            logger.error("获取竞猜记录错误! 无法为玩家兑现竞猜奖励");
            return;
        }

        if (CollectionUtils.isEmpty(r.data)) {
            return;
        }

        EliteRaceKV kv = role.getGame().pvp.eliteRace.getDataManager().getData();
        for (EliteRaceBetRecord betRecord : r.data) {
            EliteRaceBetVO betVO = betMap.get(betRecord.getSpec().toString());
            if (Objects.isNull(betVO) || kv.getSpec().compareTo(betRecord.getSpec()) < 0) {
                continue;
            }
            betVO.exchange = (byte) 1;
            if (betVO.getSide() == betVO.getWinner()) {
                role.getHistory().action.eliteRaceBetCorrect();
                addCoins(betVO.getGetCoins());
            } else {
                MixRes rwd = new MixRes(GDEliteRace.BET_WRONG_REWARD);
                rwd.add(role);
                role.getGame().notice.dialogReward(role, rwd);
            }
        }
    }

    public void onSeasonSwitch() {
        rdMap.clear();
    }
}
